#!/usr/bin/env python
#-*- coding: utf-8 -*-
import gtk

class GtkMenuFactory(object):
	@staticmethod
	def onSelectionDone(menu):
		menu.destroy()
	
	def __init__(self, menuDefinition, screen = None):
		self.menuDefinition = menuDefinition
		self.screen = screen
		self.menu = None
		
	def create(self):
		if not self.menu:
			self.menu = self.generate()
		return self.menu
		
	def generate(self):
		menu = gtk.Menu()
		if self.screen:
			menu.set_screen(self.screen)
		menu.connect('selection-done', GtkMenuFactory.onSelectionDone)
		for itemDefinition in self.menuDefinition:
			menuItem = self.generateMenuItems(itemDefinition)
			menu.append(menuItem)
		menu.show_all()
		return menu
	
	def generateMenuItems(self, itemDefinition):
		name = itemDefinition[0]
		userParameters = itemDefinition[2:]
		menuItem = gtk.MenuItem(name, True)
		
		if isinstance(itemDefinition[1], list) or isinstance(itemDefinition[1], tuple):
			subMenuDefinition = itemDefinition[1]
			subMenu = gtk.Menu()
			subMenu.connect('selection-done', GtkMenuFactory.onSelectionDone)
			
			for subItemDefinition in subMenuDefinition:
				subItem = self.generateMenuItems(subItemDefinition)
				subMenu.append(subItem)
			menuItem.set_submenu(subMenu)
			
		elif callable(itemDefinition[1]):
			menuItem.connect("activate", itemDefinition[1], *userParameters)
		else:
			raise Exception, "Invalid menu definition!"
		return menuItem
	
	def popup(self, event):
		self.create().popup(None, None, None, event.button, event.time)
	
if __name__ == "__main__":
	def onPopupMenuSelected(widget, param = None):
		print "%r" % param
		
	def onPress(widget, event):
		if event.button == 3:
			subMenu = [
				["Inner one", onPopupMenuSelected, "Inner one selected"],
				["Inner two", onPopupMenuSelected, "Inner two selected"]]
			
			menu = [
				["Outer", subMenu], 
				["Alone", onPopupMenuSelected, "Alone selected"]]
				
			gtkMenuFactory = GtkMenuFactory(menu)
			gtkMenuFactory.popup(event)
			
	window = gtk.Window(gtk.WINDOW_TOPLEVEL)
	window.connect('delete-event', gtk.main_quit)
	button = gtk.Button("some")
	button.connect("button-press-event", onPress)
	window.add(button)
	window.show_all()
	gtk.main()
